﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using LaughingDog.GameObjects;
using LaughingDog.Components.Shapes;
using LaughingDog.Components;
using FarseerGames.FarseerPhysics.Collisions;

namespace LaughingDog
{
    /// <summary>
    /// A static class that can be used to ease the creation of shapes.
    /// </summary>
    public static class Shapes
    {
        /// <summary>
        /// Creates a Shape of the specified type.        
        /// </summary>
        /// <typeparam name="T">The type of Shape to create.</typeparam>
        /// <returns>The created Shape.</returns>
        public static T CreateShape<T>() where T : Shape
        {
            GameObject gameObject = new GameObject();          
            T shape = gameObject.AddComponent<T>();

            return shape;
        }        

        /// <summary>
        /// Creates a Line.
        /// </summary>
        /// <returns>The created Line.</returns>
        public static LineShape CreateLine()
        {
            return CreateShape<LineShape>();
        }

        /// <summary>
        /// Creates a Line.
        /// </summary>
        /// <param name="start">The start point of the Line.</param>
        /// <param name="end">The end point of the Line.</param>
        /// <returns>The created Line.</returns>
        public static LineShape CreateLine(Vector2 startPoint, Vector2 endPoint)
        {
            return CreateLine(startPoint, endPoint, 1, Color.White);
        }

        /// <summary>
        /// Creates a Line.
        /// </summary>
        /// <param name="start">The start point of the Line.</param>
        /// <param name="end">The end point of the Line.</param>
        /// <param name="lineThickness">The thickness of the shapes line.</param>
        /// <param name="colour">The colour of the shapes line.</param>
        /// <returns>The created Line.</returns>
        public static LineShape CreateLine(Vector2 startPoint, Vector2 endPoint, Single lineThickness, Color colour)
        {
            LineShape shape = CreateLine();

            shape.StartPoint = startPoint;
            shape.EndPoint = endPoint;
            shape.LineThickness = lineThickness;
            shape.Colour = colour;

            return shape;
        }

        /// <summary>
        /// Creates a Triangle.
        /// </summary>
        /// <returns>The created Triangle.</returns>
        public static TriangleShape CreateTriangle()
        {
            return CreateShape<TriangleShape>();
        }

        /// <summary>
        /// Creates a Triangle.
        /// </summary>
        /// <param name="pointA">The position of the first corner of the Triangle.</param>
        /// <param name="pointB">The position of the second corner of the Triangle.</param>
        /// <param name="pointC">The position of the third corner of the Triangle.</param>
        /// <returns>The created Triangle.</returns>
        public static TriangleShape CreateTriangle(Vector2 pointA, Vector2 pointB, Vector2 pointC)
        {
            return CreateTriangle(pointA, pointB, pointC, 1, Color.White);
        }

        /// <summary>
        /// Creates a Triangle.
        /// </summary>
        /// <param name="pointA">The position of the first corner of the Triangle.</param>
        /// <param name="pointB">The position of the second corner of the Triangle.</param>
        /// <param name="pointC">The position of the third corner of the Triangle.</param>
        /// <param name="lineThickness">The thickness of the shapes line.</param>
        /// <param name="colour">The colour of the shapes line.</param>
        /// <returns>The created Triangle.</returns>
        public static TriangleShape CreateTriangle(Vector2 pointA, Vector2 pointB, Vector2 pointC, Single lineThickness, Color colour)
        {
            TriangleShape shape = CreateTriangle();

            shape.PointA = pointA;
            shape.PointB = pointB;
            shape.PointC = pointC;
            shape.LineThickness = lineThickness;
            shape.Colour = colour;

            return shape;
        }

        /// <summary>
        /// Creates a Circle.
        /// </summary>
        /// <returns>The created Circle.</returns>
        public static CircleShape CreateCircle()
        {
            return CreateShape<CircleShape>();
        }

        /// <summary>
        /// Creates a Circle.
        /// </summary>
        /// <param name="position">The position of the Circle.</param>
        /// <param name="radius">The radius of the Circle.</param>
        /// <param name="numberOfSides">The number of sides to use to create the Circle. Use a higher number for greater resolution but lower performance.</param>
        /// <returns>The created Circle.</returns>
        public static CircleShape CreateCircle(Vector2 position, Single radius, Int32 numberOfSides)
        {
            return CreateCircle(position, radius, numberOfSides, 1, Color.White);
        }

        /// <summary>
        /// Creates a Circle.
        /// </summary>
        /// <param name="position">The position of the Circle.</param>
        /// <param name="radius">The radius of the Circle.</param>
        /// <param name="numberOfSides">The number of sides to use to create the Circle. Use a higher number for greater resolution but lower performance.</param>
        /// <param name="lineThickness">The thickness of the shapes line.</param>
        /// <param name="colour">The colour of the shapes line.</param>
        /// <returns>The created Circle.</returns>
        public static CircleShape CreateCircle(Vector2 position, Single radius, Int32 numberOfSides, Single lineThickness, Color colour)
        {
            CircleShape shape = CreateCircle();

            shape.GameObject.Transform.Position = position;
            shape.Radius = radius;
            shape.NumberOfSides = numberOfSides;
            shape.LineThickness = lineThickness;
            shape.Colour = colour;

            return shape;
        }

        /// <summary>
        /// Creates an Ellipse.
        /// </summary>
        /// <returns>The created Ellipse.</returns>
        public static EllipseShape CreateEllipse()
        {
            return CreateShape<EllipseShape>();
        }

        /// <summary>
        /// Creates an Ellipse.
        /// </summary>
        /// <param name="position">The position of the Ellipse.</param>
        /// <param name="radius">The radius (both width and height) of the Ellipse.</param>
        /// <param name="numberOfSides">The number of sides to use to create the Ellipse. Use a higher number for greater resolution but lower performance.</param>
        /// <returns>The created Ellipse.</returns>
        public static EllipseShape CreateEllipse(Vector2 position, Vector2 radius, Int32 numberOfSides)
        {
            return CreateEllipse(position, radius, numberOfSides, 1, Color.White);
        }

        /// <summary>
        /// Creates an Ellipse.
        /// </summary>
        /// <param name="position">The position of the Ellipse.</param>
        /// <param name="radius">The radius (both width and height) of the Ellipse.</param>
        /// <param name="numberOfSides">The number of sides to use to create the Ellipse. Use a higher number for greater resolution but lower performance.</param>
        /// <param name="lineThickness">The thickness of the shapes line.</param>
        /// <param name="colour">The colour of the shapes line.</param>
        /// <returns>The created Ellipse.</returns>
        public static EllipseShape CreateEllipse(Vector2 position, Vector2 radius, Int32 numberOfSides, Single lineThickness, Color colour)
        {
            EllipseShape shape = CreateEllipse();

            shape.GameObject.Transform.Position = position;
            shape.Radius = radius;
            shape.NumberOfSides = numberOfSides;
            shape.LineThickness = lineThickness;
            shape.Colour = colour;

            return shape;
        }

        /// <summary>
        /// Creates a Polygon.
        /// </summary>
        /// <returns>The created Polygon.</returns>
        public static PolygonShape CreatePolygon()
        {
            return CreateShape<PolygonShape>();
        }

        /// <summary>
        /// Creates a Polygon.
        /// </summary>
        /// <param name="position">The position of the Polygon.</param>
        /// <param name="vectors">A list of Vector2s to use for the Polygon.</param>
        /// <returns>The created Polygon.</returns>
        public static PolygonShape CreatePolygon(Vector2 position, List<Vector2> vectors)
        {
            return CreatePolygon(position, vectors, 1, Color.White);            
        }

        /// <summary>
        /// Creates a Polygon from a Texture2D.
        /// </summary>
        /// <param name="position">The position of the Polygon.</param>
        /// <param name="texture">The texture that you would like to use to create the Polygon.</param>
        /// <returns>The created Polygon.</returns>
        public static PolygonShape CreatePolygon(Vector2 position, Texture2D texture)
        {
            return CreatePolygon(position, texture, 1, Color.White);
        }

        /// <summary>
        /// Creates a Polygon.
        /// </summary>
        /// <param name="position">The position of the Polygon.</param>
        /// <param name="vectors">A list of Vector2s to use for the Polygon.</param>
        /// <param name="lineThickness">The thickness of the shapes line.</param>
        /// <param name="colour">The colour of the shapes line.</param>
        /// <returns>The created Polygon.</returns>
        public static PolygonShape CreatePolygon(Vector2 position, List<Vector2> vectors, Single lineThickness, Color colour)
        {
            PolygonShape shape = CreatePolygon();

            shape.GameObject.Transform.Position = position;
            shape.SetVectors(vectors);
            shape.LineThickness = lineThickness;
            shape.Colour = colour;

            return shape;
        }

        /// <summary>
        /// Creates a Polygon from a Texture2D.
        /// </summary>
        /// <param name="position">The position of the Polygon.</param>
        /// <param name="texture">The texture that you would like to use to create the Polygon.</param>
        /// <param name="lineThickness">The thickness of the shapes line.</param>
        /// <param name="colour">The colour of the shapes line.</param>
        /// <returns>The created Polygon.</returns>
        public static PolygonShape CreatePolygon(Vector2 position, Texture2D texture, Single lineThickness, Color colour)
        {
            PolygonShape polygon;
            
            uint[] textureData = new uint[texture.Width * texture.Height];
            texture.GetData(textureData);

            Vertices verts = Vertices.CreatePolygon(textureData, texture.Width, texture.Height);
            
            polygon = CreatePolygon(position, verts, 1, Color.White);

            polygon.Join();

            return polygon;
        }
    }
}
